package com.jichangxiu.flow.server.core.context;

import cn.hutool.core.util.ObjectUtil;
import com.jichangxiu.flow.server.core.entity.Bo.EdgeBo;
import com.jichangxiu.flow.server.core.entity.Bo.NodeBo;
import com.jichangxiu.flow.server.core.entity.dto.Edge;
import com.jichangxiu.flow.server.core.entity.dto.Node;
import com.jichangxiu.flow.server.core.utils.TreeUtils;
import lombok.Data;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * LogicFlowContext:
 *
 * @author Jcx
 * @create 2025-01-01 00:00:00
 */
@Data
public class LiteFlowContext {

    private NodeBo rootNodeBo;

    private List<Node> nodeList;

    private List<Edge> edgeList;

    private List<NodeBo> nodeBoList;

    private List<EdgeBo> edgeBoList;

    private Map<String, Node> idByNodeToMap;

    private Map<String, List<Edge>> sourceIdByEdgeListToMap;

    private Map<String, List<Edge>> targetIdByEdgeListToMap;

    private Map<String, NodeBo> idByNodeBoToMap;

    private Map<String, List<EdgeBo>> sourceIdByEdgeBoListToMap;

    private Map<String, List<EdgeBo>> targetIdByEdgeBoListToMap;

    public LiteFlowContext() {
    }

    public LiteFlowContext(List<Node> nodeList, List<Edge> edgeList, List<NodeBo> nodeBoList, List<EdgeBo> edgeBoList, Map<String, Node> idByNodeToMap, Map<String, List<Edge>> sourceIdByEdgeListToMap, Map<String, List<Edge>> targetIdByEdgeListToMap, Map<String, NodeBo> idByNodeBoToMap, Map<String, List<EdgeBo>> sourceIdByEdgeBoListToMap, Map<String, List<EdgeBo>> targetIdByEdgeBoListToMap) {
        this.nodeList = nodeList;
        this.edgeList = edgeList;
        this.nodeBoList = nodeBoList;
        this.edgeBoList = edgeBoList;
        this.idByNodeToMap = idByNodeToMap;
        this.sourceIdByEdgeListToMap = sourceIdByEdgeListToMap;
        this.targetIdByEdgeListToMap = targetIdByEdgeListToMap;
        this.idByNodeBoToMap = idByNodeBoToMap;
        this.sourceIdByEdgeBoListToMap = sourceIdByEdgeBoListToMap;
        this.targetIdByEdgeBoListToMap = targetIdByEdgeBoListToMap;
    }

    public static LiteFlowContext buildLogicFlowContext(List<Node> nodeList, List<Edge> edgeList) {
        if (ObjectUtil.isEmpty(nodeList) || ObjectUtil.isEmpty(edgeList))
            throw new RuntimeException("逻辑流程图解析失败");
        LiteFlowContext liteFlowContext = new LiteFlowContext();
        if (ObjectUtil.isNotEmpty(edgeList)) {
            liteFlowContext.setEdgeList(edgeList);
            List<EdgeBo> edgeBoList = edgeList.stream().map(EdgeBo::initEdgeBo).collect(Collectors.toList());
            liteFlowContext.setEdgeBoList(edgeBoList);
            liteFlowContext.setSourceIdByEdgeBoListToMap(edgeBoList.stream().collect(Collectors.groupingBy(EdgeBo::getSourceNodeId)));
            liteFlowContext.setTargetIdByEdgeBoListToMap(edgeBoList.stream().collect(Collectors.groupingBy(EdgeBo::getTargetNodeId)));
            Map<String, List<Edge>> sourceIdByEdgeListToMap = edgeList.stream().collect(Collectors.groupingBy(Edge::getSourceNodeId));
            liteFlowContext.setSourceIdByEdgeListToMap(sourceIdByEdgeListToMap);
            Map<String, List<Edge>> targetIdByEdgeListToMap = edgeList.stream().collect(Collectors.groupingBy(Edge::getTargetNodeId));
            liteFlowContext.setTargetIdByEdgeListToMap(targetIdByEdgeListToMap);
            if (ObjectUtil.isNotEmpty(nodeList)) {
                liteFlowContext.setNodeList(nodeList);
                liteFlowContext.setIdByNodeToMap(nodeList.stream().collect(Collectors.toMap(Node::getId, Function.identity())));
                List<NodeBo> nodeBoList = nodeList.stream().map(node -> NodeBo.initNodeBo(node, sourceIdByEdgeListToMap, targetIdByEdgeListToMap)).collect(Collectors.toList());
                // 给循环节点设置父节点 id
                TreeUtils.setNodeBoCycleParentId(nodeBoList);
                liteFlowContext.setNodeBoList(nodeBoList);
                liteFlowContext.setIdByNodeBoToMap(nodeBoList.stream().collect(Collectors.toMap(NodeBo::getId, Function.identity())));
            }
        }
        return liteFlowContext;
    }

    public static LiteFlowContext buildLogicFlowContext(String cycleParentId, List<Node> nodeList, List<Edge> edgeList) {
        if (ObjectUtil.isEmpty(nodeList) || ObjectUtil.isEmpty(edgeList))
            throw new RuntimeException("逻辑流程图解析失败");
        LiteFlowContext liteFlowContext = new LiteFlowContext();
        if (ObjectUtil.isNotEmpty(edgeList)) {
            liteFlowContext.setEdgeList(edgeList);
            List<EdgeBo> edgeBoList = edgeList.stream().map(EdgeBo::initEdgeBo).collect(Collectors.toList());
            liteFlowContext.setEdgeBoList(edgeBoList);
            liteFlowContext.setSourceIdByEdgeBoListToMap(edgeBoList.stream().collect(Collectors.groupingBy(EdgeBo::getSourceNodeId)));
            liteFlowContext.setTargetIdByEdgeBoListToMap(edgeBoList.stream().collect(Collectors.groupingBy(EdgeBo::getTargetNodeId)));
            Map<String, List<Edge>> sourceIdByEdgeListToMap = edgeList.stream().collect(Collectors.groupingBy(Edge::getSourceNodeId));
            liteFlowContext.setSourceIdByEdgeListToMap(sourceIdByEdgeListToMap);
            Map<String, List<Edge>> targetIdByEdgeListToMap = edgeList.stream().collect(Collectors.groupingBy(Edge::getTargetNodeId));
            liteFlowContext.setTargetIdByEdgeListToMap(targetIdByEdgeListToMap);
            if (ObjectUtil.isNotEmpty(nodeList)) {
                liteFlowContext.setNodeList(nodeList);
                liteFlowContext.setIdByNodeToMap(nodeList.stream().collect(Collectors.toMap(Node::getId, Function.identity())));
                List<NodeBo> nodeBoList = nodeList.stream().map(node -> NodeBo.initNodeBo(node, sourceIdByEdgeListToMap, targetIdByEdgeListToMap)).collect(Collectors.toList());
                // 给循环节点设置父节点 id
                nodeBoList.forEach(nodeBo -> nodeBo.setCycleParentId(cycleParentId));
                liteFlowContext.setNodeBoList(nodeBoList);
                liteFlowContext.setIdByNodeBoToMap(nodeBoList.stream().collect(Collectors.toMap(NodeBo::getId, Function.identity())));
            }
        }
        return liteFlowContext;
    }

}
